﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Data.Objects;
using EF_Model;
using Moq;
using System.Collections.Generic;
using System.Linq;

namespace EF_Tests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod_Mock_Write()
        {
            //although no database interaction will be happened, but the corresponding web.config entry is needed
            Mock<DatabaseContext> dbContext = new Mock<DatabaseContext>();
            CustomerRepository cr = new CustomerRepository(dbContext.Object);

            //DatabaseContext dbContext = new DatabaseContext();
            //CustomerRepository cr = new CustomerRepository(dbContext);

            
            Customer c = new Customer();
            c.CustomerID = "008";
            c.ContactName = "xxx";
            c.CompanyName = "com-001";

            dbContext.Setup(db => db.ObjectSet<Customer>()).Returns(new FakeObjectSet<Customer>());

            /*
             Test method EF_Tests.UnitTest1.TestMethod_Mock_Write threw exception: 
             System.NullReferenceException: Object reference not set to an instance of an object.
                To remove this error we need to declare public ObjectSet<Customer> Customers as non-virtual
             */
            //mock database write is being happened
            cr.AddCustomer(c);
            cr.SaveChanges();
            
        }

        [TestMethod]
        public void tmp1()
        {
            DatabaseContext dbContext2 = new DatabaseContext();
            var first = dbContext2.Customers.FirstOrDefault(c => c.CustomerID == "001");
            //var first = dbContext.Object.Customers.FirstOrDefault(c => c.CustomerID == "118");
        }

        [TestMethod]
        public void TestMethod_Mock_Read()
        {
            //although no database interaction will be happened, but the corresponding web.config entry is needed
            Mock<DatabaseContext> dbContext = new Mock<DatabaseContext>();
            CustomerRepository cr = new CustomerRepository(dbContext.Object);

            //DatabaseContext dbContext = new DatabaseContext();
            //CustomerRepository cr = new CustomerRepository(dbContext);

            Customer c = new Customer();
            c.CustomerID = "118";
            c.ContactName = "xxx-118";
            c.CompanyName = "com-001";

            //setting up the mock database
            ObjectSet<Customer> customerObjectSet = dbContext.Object.CreateObjectSet<Customer>();
            customerObjectSet.AddObject(c);
            
            /* 
            Test method EF_Tests.UnitTest1.TestMethod_Mock_Read threw exception: 
            System.ArgumentException: Invalid setup on a non-overridable member:
            db => db.Customers 
                To remove this error we need to declare public ObjectSet<Customer> Customers as virtual
             */
            dbContext.Setup(db => db.Customers).Returns(customerObjectSet);

            //////////////////////////////
            
            //actual database read is being happened
            //???? why this code is hooking in the physical database, although we have mock setup for customer??
            //var first = dbContext.Object.Customers.FirstOrDefault(c1 => c1.CustomerID == "118");
            Customer first = cr.GetById("001");
            System.Console.WriteLine(first.ContactName);

            ///////////////////
            

        }

        [TestMethod]
        public void TestMethod_Mock_Read_With_Fake_Object()
        {
            //although no database interaction will be happened, but the corresponding web.config entry is needed
            Mock<DatabaseContext> dbContext = new Mock<DatabaseContext>();
            CustomerRepository cr = new CustomerRepository(dbContext.Object);

            //DatabaseContext dbContext = new DatabaseContext();
            //CustomerRepository cr = new CustomerRepository(dbContext);

            Customer c = new Customer();
            c.CustomerID = "118";
            c.ContactName = "xxx-118";
            c.CompanyName = "com-001";

            //setting up the mock database
            //ObjectSet<Customer> customerObjectSet = dbContext.Object.CreateObjectSet<Customer>();
            //customerObjectSet.AddObject(c);
            //FakeObjectSet<Customer> customerObjectSet = new FakeObjectSet<Customer>();
            //customerObjectSet.AddObject(c);
            var customers = new List<Customer> { c };
            var customerObjectSet = new Mock<FakeObjectSet<Customer>>(customers);
            
            /* 
            Test method EF_Tests.UnitTest1.TestMethod_Mock_Read threw exception: 
            System.ArgumentException: Invalid setup on a non-overridable member:
            db => db.Customers 
                To remove this error we need to declare public ObjectSet<Customer> Customers as virtual
             */
            //dbContext.Setup(db => db.Customers).Returns(customerObjectSet);
            //dbContext.Setup(db => db.Customers).Returns(customerObjectSet.Object);
            dbContext.Setup(db => db.ObjectSet<Customer>()).Returns(customerObjectSet.Object);
            //////////////////////////////
            IObjectSet<Customer> customerObjectSet1 = dbContext.Object.Customers;
            Customer cA = customerObjectSet1.Single(c1 => c1.CustomerID == "118");
            System.Console.WriteLine(cA.ContactName);
            //////////////////////////////

            //actual database read is being happened
            //???? why this code is hooking in the physical database, although we have mock setup for customer??
            //var first = dbContext.Object.Customers.FirstOrDefault(c1 => c1.CustomerID == "118");
            //Customer first = cr.GetById("001");
            //System.Console.WriteLine(first.ContactName);

            ///////////////////


        }


        [TestMethod]
        public void TestMethod_Mock_Read_With_Fake_Object_2()
        {
            //although no database interaction will be happened, but the corresponding web.config entry is needed
            Mock<DatabaseContext> dbContext = new Mock<DatabaseContext>();
            CustomerRepository cr = new CustomerRepository(dbContext.Object);

            //DatabaseContext dbContext = new DatabaseContext();
            //CustomerRepository cr = new CustomerRepository(dbContext);

            Customer c = new Customer();
            c.CustomerID = "118";
            c.ContactName = "xxx-118";
            c.CompanyName = "com-001-xx";

            //setting up the mock database
            //ObjectSet<Customer> customerObjectSet = dbContext.Object.CreateObjectSet<Customer>();
            //customerObjectSet.AddObject(c);
            //FakeObjectSet<Customer> customerObjectSet = new FakeObjectSet<Customer>();
            //customerObjectSet.AddObject(c);
            
            /*var customers = new List<Customer> { c };
            var customerObjectSet = new Mock<FakeObjectSet<Customer>>();
            customerObjectSet.Object.AddObject(c);*/

            //FakeObjectSet<Customer> customerObjectSet = new FakeObjectSet<Customer>();
            //IObjectSet<Customer> customerObjectSet = dbContext.Object.ObjectSet<Customer>();
            
            /* 
            Test method EF_Tests.UnitTest1.TestMethod_Mock_Read threw exception: 
            System.ArgumentException: Invalid setup on a non-overridable member:
            db => db.Customers 
                To remove this error we need to declare public ObjectSet<Customer> Customers as virtual
             */
            //dbContext.Setup(db => db.Customers).Returns(customerObjectSet);
            
            /*ObjectSet<Customer> customerObjectSet = dbContext.Object.CreateObjectSet<Customer>();
            customerObjectSet.AddObject(c);//really not adds anything!! this may because the dbContext is a mock object. To add it a concrete implementation is needed for dbContext
            dbContext.Setup(db => db.Customers).Returns(customerObjectSet);*/
            dbContext.Object.Customers.AddObject(c);

            //////////////////////////////
            IObjectSet<Customer> customerObjectSet1 = dbContext.Object.Customers;
            Customer cA = customerObjectSet1.Single(c1 => c1.CustomerID == "118");
            System.Console.WriteLine(cA.ContactName);
            //////////////////////////////

            //actual database read is being happened
            //???? why this code is hooking in the physical database, although we have mock setup for customer??
            //var first = dbContext.Object.Customers.FirstOrDefault(c1 => c1.CustomerID == "118");
            //Customer first = cr.GetById("001");
            //System.Console.WriteLine(first.ContactName);

            ///////////////////


        }
        //[TestMethod]
        //public void TestMethod_Mock_Read_With_Fake_ObjectSet()
        //{
        //    //although no database interaction will be happened, but the corresponding web.config entry is needed
        //    Mock<DatabaseContext> dbContext = new Mock<DatabaseContext>();
        //    CustomerRepository cr = new CustomerRepository(dbContext.Object);

        //    //DatabaseContext dbContext = new DatabaseContext();
        //    //CustomerRepository cr = new CustomerRepository(dbContext);

        //    Customer c = new Customer();
        //    c.CustomerID = "118";
        //    c.ContactName = "xxx-118";
        //    c.CompanyName = "com-001";

        //    //setting up the mock database
        //    List<Customer> customers = new List<Customer> { c };
        //    Mock<FakeObjectSet<Customer>> customerObjectSet = new Mock<FakeObjectSet<Customer>>(customers);
        //    //dbContext.Setup(db => db.Customers).Returns(customerObjectSet.Object);

        //    //actual database read is being happened
        //    //System.Console.WriteLine(cr.GetById("118").ContactName);

        //}
    }
}
